<?php

class ActiveGoodsLogicResult
{
    private $redis;
    private $stockPrefix;
    private $userPrefix;
    private $statusPrefix;
    private $lockPrefix;

    /**
     * 构造函数
     *
     * @param string $stockPrefix Redis库存键前缀
     * @param string $userPrefix Redis用户抢购键前缀
     * @param string $statusPrefix Redis活动状态键前缀
     * @param string $lockPrefix Redis锁键前缀
     */
    public function __construct($stockPrefix = 'active_goods_stock_', $userPrefix = 'user_purchase_', $statusPrefix = 'active_status_', $lockPrefix = 'lock_user_')
    {
        // 初始化 Redis 连接
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);

        // 设置 Redis 键前缀
        $this->stockPrefix = $stockPrefix;
        $this->userPrefix = $userPrefix;
        $this->statusPrefix = $statusPrefix;
        $this->lockPrefix = $lockPrefix;
    }

    /**
     * 初始化活动商品库存
     *
     * @param int $activeGoodsId 活动商品ID
     * @param int $stock 初始库存数量
     * @return array 返回操作结果
     */
    public function initStock($activeGoodsId, $stock)
    {
        $stockKey = $this->stockPrefix . $activeGoodsId;
        $statusKey = $this->statusPrefix . $activeGoodsId;
        $this->redis->set($stockKey, $stock);
        $this->redis->set($statusKey, 1);  // 活动状态设置为进行中
        return ['status' => 200, 'message' => '库存初始化成功'];
    }

    /**
     * 提前结束活动
     *
     * @param int $activeGoodsId 活动商品ID
     * @return array 返回操作结果
     */
    public function endActivity($activeGoodsId)
    {
        $statusKey = $this->statusPrefix . $activeGoodsId;
        $this->redis->set($statusKey, 0);  // 活动状态设置为结束
        return ['status' => 200, 'message' => '活动已结束'];
    }

    /**
     * 秒杀抢购操作
     *
     * @param int $userId 用户ID
     * @param int $activeGoodsId 活动商品ID
     * @param int $maxAttempts 用户最大抢购次数
     * @return array 返回抢购结果
     */
    public function seckill($userId, $activeGoodsId, $maxAttempts = 1)
    {
        $stockKey = $this->stockPrefix . $activeGoodsId;
        $userKey = $this->userPrefix . $userId . '_' . $activeGoodsId;
        $statusKey = $this->statusPrefix . $activeGoodsId;
        $lockKey = $this->lockPrefix . $userId . '_' . $activeGoodsId;

        // 获取锁
        $lock = $this->acquireLock($lockKey, 5);
        if (!$lock) {
            return ['status' => 500, 'message' => '请求过于频繁，请稍后再试'];
        }

        try {
            // 检查活动是否已结束
            $status = $this->redis->get($statusKey);
            if ($status == 0) {
                return ['status' => 500, 'message' => '活动已结束'];
            }

            // 获取当前用户已抢购次数
            $attempts = $this->redis->get($userKey);
            if ($attempts && $attempts >= $maxAttempts) {
                return ['status' => 500, 'message' => '您已经达到最大抢购次数'];
            }

            // 执行Lua脚本来检查并扣减库存
            $luaScript = "
                local stockKey = KEYS[1]
                local userKey = KEYS[2]
                local statusKey = KEYS[3]
                local maxAttempts = tonumber(ARGV[1])
                local attempts = redis.call('get', userKey)
                local status = redis.call('get', statusKey)
                if status == '0' then
                    return -2
                end
                if attempts and tonumber(attempts) >= maxAttempts then
                    return -1
                end
                local stock = tonumber(redis.call('get', stockKey))
                if stock and stock > 0 then
                    redis.call('decr', stockKey)
                    redis.call('incr', userKey)
                    return 1
                else
                    return 0
                end
            ";

            $result = $this->redis->eval($luaScript, [$stockKey, $userKey, $statusKey], 3, $maxAttempts);

            if ($result == 1) {
                return ['status' => 200, 'message' => '抢购成功'];
            } elseif ($result == -1) {
                return ['status' => 500, 'message' => '您已经达到最大抢购次数'];
            } elseif ($result == -2) {
                return ['status' => 500, 'message' => '活动已结束'];
            } else {
                return ['status' => 500, 'message' => '库存不足，抢购失败'];
            }
        } finally {
            // 释放锁
            $this->releaseLock($lockKey);
        }
    }

    /**
     * 获取分布式锁
     *
     * @param string $lockKey 锁的键
     * @param int $expire 锁的过期时间（秒）
     * @return bool 是否获取成功
     */
    private function acquireLock($lockKey, $expire)
    {
        $isLocked = $this->redis->set($lockKey, 1, ['nx', 'ex' => $expire]);
        return $isLocked ? true : false;
    }

    /**
     * 释放分布式锁
     *
     * @param string $lockKey 锁的键
     */
    private function releaseLock($lockKey)
    {
        $this->redis->del($lockKey);
    }

    /**
     * 取消订单还原库存
     *
     * @param int $userId 用户ID
     * @param int $activeGoodsId 活动商品ID
     * @return array 返回还原结果
     */
    public function restoreStock($userId, $activeGoodsId)
    {
        $stockKey = $this->stockPrefix . $activeGoodsId;
        $userKey = $this->userPrefix . $userId . '_' . $activeGoodsId;

        // 执行Lua脚本来还原库存并删除用户抢购记录
        $luaScript = "
            local stockKey = KEYS[1]
            local userKey = KEYS[2]
            local attempts = redis.call('get', userKey)
            if attempts and tonumber(attempts) > 0 then
                redis.call('decr', userKey)
                redis.call('incr', stockKey)
                return 1
            else
                return 0
            end
        ";

        $result = $this->redis->eval($luaScript, [$stockKey, $userKey], 2);

        if ($result) {
            return ['status' => 200, 'message' => '库存已还原'];
        } else {
            return ['status' => 500, 'message' => '无有效的取消操作'];
        }
    }

    /**
     * 商家追加库存
     *
     * @param int $activeGoodsId 活动商品ID
     * @param int $additionalStock 追加的库存数量
     * @return array 返回追加结果
     */
    public function addStock($activeGoodsId, $additionalStock)
    {
        $stockKey = $this->stockPrefix . $activeGoodsId;
        $this->redis->incrby($stockKey, $additionalStock);
        return ['status' => 200, 'message' => '库存追加成功'];
    }

    /**
     * 直接扣除库存
     *
     * @param int $activeGoodsId 活动商品ID
     * @param int $deductStock 要扣除的库存数量
     * @return array 返回扣除结果
     */
    public function deductStock($activeGoodsId, $deductStock)
    {
        $stockKey = $this->stockPrefix . $activeGoodsId;
        $this->redis->decrby($stockKey, $deductStock);
        return ['status' => 200, 'message' => '库存扣除成功'];
    }
}

// 示例用法：
$logic = new ActiveGoodsLogicResult();

// 初始化库存
echo json_encode($logic->initStock($activeGoodsId, 100));

// 用户抢购，最大抢购次数为3
echo json_encode($logic->seckill($userId, $activeGoodsId, 3));

// 提前结束活动
echo json_encode($logic->endActivity($activeGoodsId));

// 取消订单还原库存
echo json_encode($logic->restoreStock($userId, $activeGoodsId));

// 商家追加库存
echo json_encode($logic->addStock($activeGoodsId, 50));

// 直接扣除库存
echo json_encode($logic->deductStock($activeGoodsId, 20));

?>
